use strict;
use DBI;
use DBD::ODBC;
use POSIX;
use Time::HiRes qw(time);
use Storable qw(dclone);
use List::Util qw(shuffle);
use List::MoreUtils qw/ uniq /;
use List::MoreUtils 'pairwise';

my $flagLowDim = 0;
my $iter = 0;

require 'CDS_FilterData.pl';

my ($CDS_HD);

open (KEYINFO, '> CDS_Keys.txt');
open (LOG, '> CDS_Log.txt');

my $BASE_HD_FILE_NAME = 'CDS_HD';

# Set connection parameters
my $dsn = 'dbi:ODBC:CDSDriver';
my ($username, $password) = ('trauma', 'trauma');
print LOG "username = $username, password = $password\n";

# Connect to the database
my $cds = DBI -> connect($dsn  ,$username,$password);

# Preparing and executing sql query
my $sql = "EXEC sp_CDS_Imputation_ExtractRelevantColsFromAllTables14";
print LOG "SQL COMMAND EXECUTED: $sql\n";

my $sth = $cds -> prepare($sql);
$sth -> execute();

# Declare hashes
my (%hUID_TREATMNT, %hUID, %hAGE, %hUID_PARUSE, %hUID_CHORIENTA, %hUID_SEATPOS_ROW, %hUID_SEATPOS_COL, %hUID_EJECTION, %hUID_GLASGOW, %hUID_AISCODE, %hUID_MANCOLL, %hUID_CLASS1, %hUID_CLASS2, %hUID_OBJCONT, %hDVTOTAL, %hUID_DVEST, %hSPLIMIT);
my (%hDEATH, %hTREATMNT, %hPARUSE, %hCHORIENTA, %hSEATPOS_ROW, %hSEATPOS_COL, %hEJECTION, %hGLASGOW, %hAISCODE, %hMANCOLL, %hCLASS1, %hCLASS2, %hOBJCONT, %hDVEST);

#########################################
# $UID = PSU_CASEID_ACCYEAR_VEHNO_OCCNO #
#########################################

# Declare corresponding hash keys
my ($DEATH, $TREATMNT, $UID, $AGE, $PARUSE, $CHORIENT, $CHORIENTA, $SEATPOS, $SEATPOS_ROW, $SEATPOS_COL, $EJECTION, $GLASGOW, $AISCODE, $MANCOLL, $CLASS1, $CLASS2, $OBJCONT, $DVTOTAL, $DVEST, $SPLIMIT);

#print LOG "iter\tUID,\tAGE\tPARUSE\tCHORIENTA\tSEATPOS_ROW\tSEATPOS_COL\tEJECTION\tGLASGOW\tAISCODE\tMANCOLL\tCLASS1\tCLASS2\tOBJCONT\tDVTOTAL\tDVEST\tSPLIMIT\n";
my $startTime = time();
my @aUID_CDS;
my %hDataType;

while(($UID, $AGE, $PARUSE, $CHORIENT, $SEATPOS, $EJECTION, $GLASGOW, $TREATMNT, $DEATH, $AISCODE, $MANCOLL, $CLASS1, $CLASS2, $OBJCONT, $DVTOTAL, $DVEST, $SPLIMIT) = $sth -> fetchrow_array())
{
    $aUID_CDS[$iter] = $UID;
    
    $iter++;

    $AISCODE  = trimIfEmpty($AISCODE);

    $DEATH = filterDeath($DEATH);
    $TREATMNT = filterTreatmnt($TREATMNT);
    $PARUSE = filterParuse($PARUSE);
    $CHORIENTA = filterChorientA($PARUSE,$CHORIENT);
    ($SEATPOS_ROW, $SEATPOS_COL) = filterSeatpos($SEATPOS);
    $EJECTION = filterEjection($EJECTION);
    $GLASGOW = filterGlasgow($GLASGOW);
    $AISCODE = filterAiscode($AISCODE);
    $MANCOLL = filterMancoll($MANCOLL);
    $CLASS1 = filterClass($CLASS1);
    $CLASS2 = filterClass($CLASS2);
    $OBJCONT = filterObjcont($OBJCONT);
    $DVTOTAL = filterDvtotal($DVTOTAL);
    $DVEST = filterDvest($DVEST);
    $SPLIMIT = filterSplimit($SPLIMIT);
    
#    print LOG "$iter\t$UID\t$AGE\t$PARUSE\t$CHORIENTA\t$SEATPOS_ROW\t$SEATPOS_COL\t$EJECTION\t$GLASGOW\t$AISCODE\t$MANCOLL\t$CLASS1\t$CLASS2\t$OBJCONT\t$DVTOTAL\t$DVEST\t$SPLIMIT\n";
    
    # Start filling hashes
    $hUID{$UID} = 1;
    $hDEATH{$UID} = $DEATH;
    $hUID_TREATMNT{$UID}{$TREATMNT} = 1;
    $hAGE{$UID} = $AGE;
    $hUID_PARUSE{$UID}{$PARUSE} = 1;
    $hUID_CHORIENTA{$UID}{$CHORIENTA} = 1;
    $hUID_SEATPOS_ROW{$UID}{$SEATPOS_ROW} = 1;
    $hUID_SEATPOS_COL{$UID}{$SEATPOS_COL} = 1;
    $hUID_EJECTION{$UID}{$EJECTION} = 1;
    $hUID_GLASGOW{$UID}{$GLASGOW} = 1;
    $hUID_AISCODE{$UID}{$AISCODE} = 1;
    $hUID_MANCOLL{$UID}{$MANCOLL} = 1;
    $hUID_CLASS1{$UID}{$CLASS1} = 1;
    $hUID_CLASS2{$UID}{$CLASS2} = 1;
    $hUID_OBJCONT{$UID}{$OBJCONT} = 1;
    $hDVTOTAL{$UID} = $DVTOTAL;
    $hUID_DVEST{$UID}{$DVEST} = 1;
    $hSPLIMIT{$UID} = $SPLIMIT;
    
    $hDataType{$UID} = 'CDS';
}

@aUID_CDS = sort(uniq(@aUID_CDS));

my $runTime = time() - $startTime;
print LOG "Processed $iter rows of SQL data.\n";
print LOG "Time taken = $runTime seconds.\n\n";

foreach my $key (sort keys(%hUID)) {
    %hTREATMNT = assignHKeys(\%{$hUID_TREATMNT{$key}},\%hTREATMNT);
    %hPARUSE = assignHKeys(\%{$hUID_PARUSE{$key}},\%hPARUSE);
    %hCHORIENTA = assignHKeys(\%{$hUID_CHORIENTA{$key}},\%hCHORIENTA);    
    %hSEATPOS_ROW = assignHKeys(\%{$hUID_SEATPOS_ROW{$key}},\%hSEATPOS_ROW);
    %hSEATPOS_COL = assignHKeys(\%{$hUID_SEATPOS_COL{$key}},\%hSEATPOS_COL);
    %hEJECTION = assignHKeys(\%{$hUID_EJECTION{$key}},\%hEJECTION);
    %hGLASGOW = assignHKeys(\%{$hUID_GLASGOW{$key}},\%hGLASGOW);
    %hAISCODE = assignHKeys(\%{$hUID_AISCODE{$key}},\%hAISCODE);
    %hMANCOLL = assignHKeys(\%{$hUID_MANCOLL{$key}},\%hMANCOLL);
    %hCLASS1 = assignHKeys(\%{$hUID_CLASS1{$key}},\%hCLASS1);
    %hCLASS2 = assignHKeys(\%{$hUID_CLASS2{$key}},\%hCLASS2);
    %hOBJCONT = assignHKeys(\%{$hUID_OBJCONT{$key}},\%hOBJCONT);
    %hDVEST = assignHKeys(\%{$hUID_DVEST{$key}},\%hDVEST);
}

my (@aInds_CDS_NULL, @aInds_CDS_Dead, @aInds_CDS_Alive);

my $counter = 0;

foreach my $key (@aUID_CDS) {
    if($hDEATH{$key} eq "NULL") {
        push(@aInds_CDS_NULL, $counter);
    } elsif($hDEATH{$key} == 1) {
        push(@aInds_CDS_Dead, $counter);
    } else {
        push(@aInds_CDS_Alive, $counter);
    }   
    $counter++;
}

my @aUID = @aUID_CDS;

# printing some counts
print LOG "Counts:\n------------------------------------------\n";
print LOG "TREATMNT\n";
foreach my $i (sort keys %hTREATMNT) {
    print LOG "$i $hTREATMNT{$i}\n";
}
print LOG "\nPARUSE\n";
foreach my $i (sort keys %hPARUSE) {
    print LOG "$i $hPARUSE{$i}\n";
}
print LOG "\nCHORIENTA\n";
foreach my $i (sort keys %hCHORIENTA) {
    print LOG "$i $hCHORIENTA{$i}\n";
}
print LOG "\nSEATPOS_ROW\n";
foreach my $i (sort keys %hSEATPOS_ROW) {
    print LOG "$i $hSEATPOS_ROW{$i}\n";
}
print LOG "\nSEATPOS_COL\n";
foreach my $i (sort keys %hSEATPOS_COL) {
    print LOG "$i $hSEATPOS_COL{$i}\n";
}
print LOG "\nEJECTION\n";
foreach my $i (sort keys %hEJECTION) {
    print LOG "$i $hEJECTION{$i}\n";
}
print LOG "\nGLASGOW\n";
foreach my $i (sort keys %hGLASGOW) {
    print LOG "$i $hGLASGOW{$i}\n";
}
print LOG "\nAISCODE\n";
foreach my $i (sort keys %hAISCODE) {
    print LOG "$i $hAISCODE{$i}\n";
}
print LOG "\nMANCOLL\n";
foreach my $i (sort keys %hMANCOLL) {
    print LOG "$i $hMANCOLL{$i}\n";
}
print LOG "\nCLASS1\n";
foreach my $i (sort keys %hCLASS1) {
    print LOG "$i $hCLASS1{$i}\n";
}
print LOG "\nCLASS2\n";
foreach my $i (sort keys %hCLASS2) {
    print LOG "$i $hCLASS2{$i}\n";
}
print LOG "\nOBJCONT\n";
foreach my $i (sort keys %hOBJCONT) {
    print LOG "$i $hOBJCONT{$i}\n";
}
print LOG "\nDVEST\n";
foreach my $i (sort keys %hDVEST) {
    print LOG "$i $hDVEST{$i}\n";
}


# Note: 1=age, 2=gender, 3=sysbp, 4=resprate, 5=pulse
print KEYINFO "seq=1: Intercept\n";
print KEYINFO "seq=2: Age\n";
print KEYINFO "seq=3: DVTOTAL\n";
print KEYINFO "seq=4: SPLIMIT\n";
print KEYINFO "\n";

my $seqNum = 5;

# assign sequence number for TREATMNT.
#foreach my $i (sort keys %hTREATMNT) {
#    $hTREATMNT{$i}=$seqNum;
#    $seqNum++;        
#}
#print KEYINFO "TREATMNT Keys... ". (keys %hTREATMNT) ." keys\n";
#foreach my $i (sort keys %hTREATMNT) {
#    print KEYINFO "seq=$hTREATMNT{$i}: TREATMNT=$i\n";
#}
#print KEYINFO "\n";

# assign sequence number for PARUSE.
foreach my $i (sort keys %hPARUSE) {
    $hPARUSE{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "PARUSE Keys... ". (keys %hPARUSE) ." keys\n";
foreach my $i (sort keys %hPARUSE) {
    print KEYINFO "seq=$hPARUSE{$i}: PARUSE=$i\n";
}
print KEYINFO "\n";

# assign sequence number for CHORIENTA.
foreach my $i (sort keys %hCHORIENTA) {
    $hCHORIENTA{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "CHORIENTA Keys... ". (keys %hCHORIENTA) ." keys\n";
foreach my $i (sort keys %hCHORIENTA) {
    print KEYINFO "seq=$hCHORIENTA{$i}: CHORIENTA=$i\n";
}
print KEYINFO "\n";

# assign sequence number for SEATPOS_ROW
foreach my $i (sort keys %hSEATPOS_ROW){
    $hSEATPOS_ROW{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "SEATPOS_ROW Keys... ". (keys %hSEATPOS_ROW) ." keys\n";
foreach my $i (sort keys %hSEATPOS_ROW){
    print KEYINFO "seq=$hSEATPOS_ROW{$i}, SEATPOS_ROW=$i\n";
}
print KEYINFO "\n";

# assign sequence number for SEATPOS_COL 
foreach my $i (sort keys %hSEATPOS_COL){
    $hSEATPOS_COL{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "SEATPOS_COL Keys... ". (keys %hSEATPOS_COL) ." keys\n";
foreach my $i (sort keys %hSEATPOS_COL){
    print KEYINFO "seq=$hSEATPOS_COL{$i}, SEATPOS_COL=$i\n";
}
print KEYINFO "\n";

# assign sequence number for EJECTION
foreach my $i (sort keys %hEJECTION){
    $hEJECTION{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "EJECTION Keys... ". (keys %hEJECTION) ." keys\n";
foreach my $i (sort keys %hEJECTION){
    print KEYINFO "seq=$hEJECTION{$i}, EJECTION=$i\n";
}
print KEYINFO "\n";

# assign sequence number for GLASGOW
foreach my $i (sort keys %hGLASGOW){
    $hGLASGOW{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "GLASGOW Keys... ". (keys %hGLASGOW) ." keys\n";
foreach my $i (sort keys %hGLASGOW){
    print KEYINFO "seq=$hGLASGOW{$i}, GLASGOW=$i\n";
}
print KEYINFO "\n";

# assign sequence number for AISCODE
foreach my $i (sort keys %hAISCODE){
    $hAISCODE{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "AISCODE Keys... ". (keys %hAISCODE) ." keys\n";
foreach my $i (sort keys %hAISCODE){
    print KEYINFO "seq=$hAISCODE{$i}: AISCODE=$i\n";
}
print KEYINFO "\n";



#my faster implementation
my $countInt = 0;
my %hTMP;
my %hAISCODE_AISCODE;

$startTime = time();
foreach my $key (sort keys %hUID_AISCODE)
{
    %hTMP = %{dclone(\%{$hUID_AISCODE{$key}})};
    foreach my $code1 (sort keys %hTMP)
    {
        delete($hTMP{$code1});  # to avoid [code1,code1] combinations
        foreach my $code2 (sort keys %hTMP)
        {
            if(!exists($hAISCODE_AISCODE{$code1}{$code2}))
            {
                $countInt++;
                print LOG "Processing two-way [AISCODE,AISCODE] interactions...$countInt\n";
                $hAISCODE_AISCODE{$code1}{$code2} = 1;
            }
        }
    }
}
foreach my $code1 (sort keys %hAISCODE_AISCODE)
{
    foreach my $code2 (sort keys %{$hAISCODE_AISCODE{$code1}})
    {
        $hAISCODE_AISCODE{$code1}{$code2} = $seqNum;
        $seqNum++;
    }
}
print KEYINFO "Two-way [AISCODE,AISCODE] Keys... $countInt keys\n";
foreach my $i (sort keys %hAISCODE_AISCODE)
{
    foreach my $j (sort keys %{$hAISCODE_AISCODE{$i}})
    {
        print KEYINFO "seq=$hAISCODE_AISCODE{$i}{$j}: [AISCODE,AISCODE]=$i, $j\n";
    }
}
print KEYINFO "\n";
$runTime = time() - $startTime;
print LOG "Processed $countInt two-way [AISCODE,AISCODE] interactions.\n";
print LOG "Time taken = $runTime seconds.\n\n";




# assign sequence number for MANCOLL
foreach my $i (sort keys %hMANCOLL){
    $hMANCOLL{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "MANCOLL Keys... ". (keys %hMANCOLL) ." keys\n";
foreach my $i (sort keys %hMANCOLL){
    print KEYINFO "seq=$hMANCOLL{$i}, MANCOLL=$i\n";
}
print KEYINFO "\n";

# assign sequence number for CLASS1
foreach my $i (sort keys %hCLASS1){
    $hCLASS1{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "CLASS1 Keys... ". (keys %hCLASS1) ." keys\n";
foreach my $i (sort keys %hCLASS1){
    print KEYINFO "seq=$hCLASS1{$i}, CLASS1=$i\n";
}
print KEYINFO "\n";

# assign sequence number for CLASS2
foreach my $i (sort keys %hCLASS2){
    $hCLASS2{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "CLASS2 Keys... ". (keys %hCLASS2) ." keys\n";
foreach my $i (sort keys %hCLASS2){
    print KEYINFO "seq=$hCLASS2{$i}, CLASS2=$i\n";
}
print KEYINFO "\n";

# assign sequence number for OBJCONT
foreach my $i (sort keys %hOBJCONT){
    $hOBJCONT{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "OBJCONT Keys... ". (keys %hOBJCONT) ." keys\n";
foreach my $i (sort keys %hOBJCONT){
    print KEYINFO "seq=$hOBJCONT{$i}, OBJCONT=$i\n";
}
print KEYINFO "\n";

# assign sequence number for DVEST
foreach my $i (sort keys %hDVEST){
    $hDVEST{$i}=$seqNum;
    $seqNum++;        
}
print KEYINFO "DVEST Keys... ". (keys %hDVEST) ." keys\n";
foreach my $i (sort keys %hDVEST){
    print KEYINFO "seq=$hDVEST{$i}, DVEST=$i\n";
}
print KEYINFO "\n";


    my ($nCDS_NULL, $nCDS_Alive, $nCDS_Dead);
    $nCDS_NULL = $#aInds_CDS_NULL + 1;
    $nCDS_Alive = $#aInds_CDS_Alive + 1;
    $nCDS_Dead = $#aUID_CDS - $nCDS_Alive - $nCDS_NULL;
    
    print "nCDSAlive = $nCDS_Alive\nnCDS_Dead = $nCDS_Dead\nnCDS_NULL = $nCDS_NULL\n";


# start to print out data
    
    my $HD_FILE_NAME = $BASE_HD_FILE_NAME . ".txt";
        
    my @aInds_selected = @aInds_CDS_NULL;
    push(@aInds_selected, @aInds_CDS_Alive);
    push(@aInds_selected, @aInds_CDS_Dead);

    my @aUID_selected = @aUID[@aInds_selected];
    
    open ($CDS_HD, '> ' , $HD_FILE_NAME); # CDS and NTDB concatenated as: CDS + NTDB_Train + CDS_Test for imputation

    my $count = -1;
            
    foreach my $key (@aUID_selected){
#        print "$key\n";
        my $index=0;
        $count++;
    
        # DEATH
        print $CDS_HD $hDEATH{$key} . " ";
        
        # Intercept    
        $index++;
        print $CDS_HD "1:1 ";
        
        # AGE    
        $index++;
        print $CDS_HD "$index:$hAGE{$key} ";
    
        # DVTOTAL
        $index++;
        print $CDS_HD "$index:$hDVTOTAL{$key} ";
        
        # SPLIMIT
        $index++;
        print $CDS_HD "$index:$hSPLIMIT{$key} ";
        
        # TREATMNT
        #foreach my $j (sort keys %{$hUID_TREATMNT{$key}}){
        #    if($j ne "NULL"){
        #        print $CDS_NTDB_HD $hTREATMNT{$j} . ":1 ";
        #        if($hDataType{$key} ne 'NTDB') {
        #            print $CDSonly_NTDB_LD $hTREATMNT{$j} . ":1 ";
        #        }
        #    }
        #    else{
        #        foreach my $k (sort keys %hTREATMNT){
        #            if($k ne "NULL"){
        #                print $CDS_NTDB_HD $hTREATMNT{$k} . ":NULL ";
        #                if($hDataType{$key} ne 'NTDB') {
        #                    print $CDSonly_NTDB_LD $hTREATMNT{$k} . ":NULL ";
        #                }
        #            }
        #        }
        #    }
        #}
        
        # PARUSE
        foreach my $j (sort keys %{$hUID_PARUSE{$key}}){
            if($j ne "NULL"){
                if($j == 5) {
                    foreach my $k (sort keys %hPARUSE){
                        if($k ne "NULL" and $k != 1 and $k != 5){
                            print $CDS_HD $hPARUSE{$k} . ":NULL ";
                        }
                    }   
                } else {
                    print $CDS_HD $hPARUSE{$j} . ":1 ";
                }
            }
            else{
                foreach my $k (sort keys %hPARUSE){
                    if($k ne "NULL" and $k != 5){
                        print $CDS_HD $hPARUSE{$k} . ":NULL ";
                    }
                }
            }
        }
        
        #CHORIENTA
        foreach my $j (sort keys %{$hUID_CHORIENTA{$key}}){
            if($j ne "NULL"){
                print $CDS_HD $hCHORIENTA{$j} . ":1 ";
            }
            else{
                foreach my $k (sort keys %hCHORIENTA){
                    if($k ne "NULL"){
                        print $CDS_HD $hCHORIENTA{$k} . ":NULL ";
                    }
                }
            }
        }
        
        #SEATPOS_ROW
        foreach my $j (sort keys %{$hUID_SEATPOS_ROW{$key}}){
            if($j ne "NULL"){
                print $CDS_HD $hSEATPOS_ROW{$j} . ":1 ";
            }
            else{
                foreach my $k (sort keys %hSEATPOS_ROW){
                    if($k ne "NULL"){
                        print $CDS_HD $hSEATPOS_ROW{$k} . ":NULL ";
                    }
                }
            }
        }
        
        #SEATPOS_COL
        foreach my $j (sort keys %{$hUID_SEATPOS_COL{$key}}){
            if($j ne "NULL"){
                print $CDS_HD $hSEATPOS_COL{$j} . ":1 ";
            }
            else{
                foreach my $k (sort keys %hSEATPOS_COL){
                    if($k ne "NULL"){
                        print $CDS_HD $hSEATPOS_COL{$k} . ":NULL ";
                    }
                }
            }
        }
        
        #EJECTION
        foreach my $j (sort keys %{$hUID_EJECTION{$key}}){
            if($j ne "NULL"){
                print $CDS_HD $hEJECTION{$j} . ":1 ";
            }
            else{
                foreach my $k (sort keys %hEJECTION){
                    if($k ne "NULL"){
                        print $CDS_HD $hEJECTION{$k} . ":NULL ";
                    }
                }
            }
        }
        
        #GLASGOW
        foreach my $j (sort keys %{$hUID_GLASGOW{$key}}){
            if($j ne "NULL"){
                print $CDS_HD $hGLASGOW{$j} . ":1 ";
            }
            else{
                foreach my $k (sort keys %hGLASGOW){
                    if($k ne "NULL"){
                        print $CDS_HD $hGLASGOW{$k} . ":NULL ";
                    }
                }
            }
        }
        
        #AISCODE
        foreach my $j (sort keys %{$hUID_AISCODE{$key}}){
            if($j ne "NULL"){
                print $CDS_HD $hAISCODE{$j} . ":1 ";
            }
        }
        
        # Two-way [AISCODE,AISCODE] codes
        %hTMP = %{dclone(\%{$hUID_AISCODE{$key}})};
        foreach my $code1(sort keys %{$hUID_AISCODE{$key}})
            {
            delete($hTMP{$code1});		# to avoid [code1,code1] combinations
            foreach my $code2(sort keys %hTMP)
            {
                print $CDS_HD $hAISCODE_AISCODE{$code1}{$code2} . ":1 ";
            }
        }

        
        #MANCOLL
        foreach my $j (sort keys %{$hUID_MANCOLL{$key}}){
            if($j ne "NULL"){
                print $CDS_HD $hMANCOLL{$j} . ":1 ";
            }
            else{
                foreach my $k (sort keys %hMANCOLL){
                    if($k ne "NULL"){
                        print $CDS_HD $hMANCOLL{$k} . ":NULL ";
                    }
                }
            }
        }
        
        #CLASS1
        foreach my $j (sort keys %{$hUID_CLASS1{$key}}){
            if($j ne "NULL"){
                print $CDS_HD $hCLASS1{$j} . ":1 ";
            }
            else{
                foreach my $k (sort keys %hCLASS1){
                    if($k ne "NULL"){
                        print $CDS_HD $hCLASS1{$k} . ":NULL ";
                    }
                }
            }
        }
        
        #CLASS2
        foreach my $j (sort keys %{$hUID_CLASS2{$key}}){
            if($j ne "NULL"){
                print $CDS_HD $hCLASS2{$j} . ":1 ";
            }
            else{
                foreach my $k (sort keys %hCLASS2){
                    if($k ne "NULL"){
                        print $CDS_HD $hCLASS2{$k} . ":NULL ";
                    }
                }
            }
        }
        
        #OBJCONT
        foreach my $j (sort keys %{$hUID_OBJCONT{$key}}){
            if($j ne "NULL"){
                print $CDS_HD $hOBJCONT{$j} . ":1 ";
            }
            else{
                foreach my $k (sort keys %hOBJCONT){
                    if($k ne "NULL"){
                        print $CDS_HD $hOBJCONT{$k} . ":NULL ";
                    }
                }
            }
        }
        
        #DVEST
        foreach my $j (sort keys %{$hUID_DVEST{$key}}){
            if($j ne "NULL"){
                print $CDS_HD $hDVEST{$j} . ":1 ";
            }
            else{
                foreach my $k (sort keys %hDVEST){
                    if($k ne "NULL"){
                        print $CDS_HD $hDVEST{$k} . ":NULL ";
                    }
                }
            }
        }
    
        print $CDS_HD "\n";
    }
    close($CDS_HD);

$cds->disconnect();
close(KEYINFO);
close(LOG);
